在網頁應用程式中,提供表單讓使用者輸入資料是常見的需求;針對表單的開發,Angular 提供了範本驅動表單 (Template-Driven Form) 與響應式表單 (Reactive Form) 兩種開發方式。這一篇將利用範本驅動表單 (Template-Driven Form) 來實作待辦事項的查詢。
實作前先修改 task-remote.service.ts 檔案,利用 json-server 提供的 API 來針對主旨與狀態進行查詢,並在 task-list.component.css 檔案加入查詢頁面所需的樣式。
@Injectable({
providedIn: "root",
})
export class TaskRemoteService {
private _url = "http://localhost:3000/tasks";
constructor(private httpClient: HttpClient) {}
getData(subject?: string, state?: number): Observable<Task[]> {
const condition = [];
if (subject) {
condition.push(`subject_like=${subject}`);
}
if (state !== undefined) {
condition.push(`state=${state}`);
}
const url = this._url + (condition.length === 0 ? "" : `?${condition.join("&")}`);
return this.httpClient.get<Task[]>(url);
}
}
.search {
padding: 10px;
}
.search div {
display: flex;
justify-content: space-between;
}
.search div.input {
margin-right: 10px;
flex-grow: 1;
display: flex;
}
.search div.input input {
flex-grow: 1;
}
.search div.button * {
margin-right: 4px;
}
Angular 把應用程式區分成頁面與資料兩部份,即便在表單開發上也是如此,Angular 將表單分成表單模型與表單樣版兩個部分。而在範本驅動表單 (Template-Driven Form) 的開發上,主要著重於表單樣版的定義,由 Angular 產生所對應的表單模型。
在開發範本驅動表單 (Template-Driven Form) 前需要匯入 FormsModule
模組,故在 task.module.ts 加入此模組的匯入。
@NgModule({
imports: [CommonModule, FormsModule, HttpClientModule],
declarations: [
TaskComponent,
TaskStateColorDirective,
TaskListComponent,
TaiwanDatePipe,
],
exports: [TaskComponent, TaskListComponent],
})
export class TaskModule {}
Angular 提供 NgModel 指令來監控如 <input>
、<select>
等表單標籤,因此在 task-list.component.html 加入查詢功能,並將 ngModel
與 task-list.component.ts 的 subject
屬性進行雙向繫結 (Two-way binding),就可以利用主旨進行查詢。
<div class="search">
<div>
<div class="input">
<input type="text" [(ngModel)]="subject" placeholder="主旨" />
</div>
<div class="button">
<button type="button" (click)="onSearch()">查詢</button>
</div>
</div>
</div>
export class TaskListComponent implements OnInit {
tasks$: Observable<Task[]>;
subject: string;
constructor(private taskService: TaskRemoteService) {}
ngOnInit(): void {
this.tasks$ = this.taskService.getData();
}
onSearch(): void {
this.tasks$ = this.taskService.getData(this.subject);
}
}
除了針對 ngModel
進行雙向繫結 (Two-way binding),也可以在 <input>
設定一範本參考變數 (Template Reference Variables),並在查詢時將值傳遞至查詢方法內。
因此,將 task-list.component.html 中的 <input>
標籤加入名稱為 '#subject' 的範本參考變數 (Template Reference Variables),並將其值設為 ngModel
;最後,再把此變數值傳入 onSearch()
方法內。
<div class="search">
<div>
<div class="input">
<input type="text" #subject="ngModel" ngModel placeholder="主旨" />
</div>
<div class="button">
<button type="button" (click)="onSearch(subject)">查詢</button>
</div>
</div>
</div>
由於 Angular 在 NgModel 指令中,設定了 'exportAs' 屬性為 'ngModel',以告知 Angular 要如何將範本參考變數 (Template Reference Variables) 連結至指令中,因此所傳入的 subject
變數為 NgModel 型別。需注意的是,此輸入表單標籤還是需要使用 NgModel 指令,否則會拋出例外。
export class TaskListComponent implements OnInit {
tasks$: Observable<Task[]>;
constructor(private taskService: TaskRemoteService) {}
onSearch(subject: NgModel): void {
this.tasks$ = this.taskService.getData(subject.value);
}
}
另外,也可以在 task-list.component.ts 利用 ViewChild 裝飾器屬性來取得 #subject
。
export class TaskListComponent implements OnInit {
@ViewChild("subject") subject: NgModel;
tasks$: Observable<Task[]>;
constructor(private taskService: TaskRemoteService) {}
onSearch(): void {
this.tasks$ = this.taskService.getData(this.subject.value);
}
}
若要利用範本驅動表單 (Template-Driven Form) 開發表單,會在頁面中使用 <form>
標籤,且在此標籤內的表單輸入標籤設定 name
屬性值。因此,在 task-list.component.html 加入主旨與狀態的查詢表單,並利用 submit
事件進行查詢。
<form class="search" #form="ngForm" (submit)="onSearch(form)">
<div>
<div class="input">
<input type="text" name="subject" #subject="ngModel" ngModel placeholder="主旨" />
<select name="status" #status="ngModel" ngModel>
<option value="">事項狀態</option>
<option value="0">未完成</option>
<option value="1">進行中</option>
<option value="2">已完成</option>
</select>
</div>
<div class="button">
<span>{{ form.value | json }}</span>
<button type="submit">查詢</button>
</div>
</div>
</form>
export class TaskListComponent implements OnInit {
tasks$: Observable<Task[]>;
constructor(private taskService: TaskRemoteService) {}
onSearch(form: NgForm): void {
const { subject, status } = form.value;
this.tasks$ = this.taskService.getData(subject, status);
}
}
在上面頁面程式中,也將 #form
資料顯示出來,從此可以看出表單模型值是利用頁面輸入標籤的 name
屬性設定所產生的。
這一篇利用查詢的實作,說明了範本驅動表單 (Template-Driven Form) 的開發,實作程式碼放在 GitHub 中,接下來將針對在此開發方式下,說明如何進行相關的表單驗證。